<script lang="tsx">
import { Component, Vue, Prop } from 'vue-property-decorator'
import { NormalizedScopedSlot, ScopedSlotChildren, VNode } from 'vue/types/vnode'
import { TableColumnPropsData, TableTdData } from './types'

@Component({
  name: 'Table',
})
export default class extends Vue {
  render() {
    return (
      <table class='table'>
        <tr>
          {this.labels.map((item, index) => {
            return <th key={index}>{item}</th>
          })}
        </tr>

        {this.rows.map((item, index) => {
          return (
            <tr key={index}>
              {item.map((it, i) => {
                return <td key={i}>{ this.parseSlot(it, index) }</td>
              })}
            </tr>
          )
        })}

        { this.$slots.default }
      </table>
    )
  }

  @Prop({ default: [] }) data!: any[]

  slots: VNode[] = []

  labels: string[] = []

  props: string[] = []

  templates: { [key: string]:NormalizedScopedSlot | undefined } = {}

  rows: TableTdData[][] = []

  mounted() {
    this.slots = this.$slots.default || []

    this.slots.forEach(slot => {
      const propsData = slot.componentOptions?.propsData as TableColumnPropsData
      this.labels.push(propsData.label)
      this.props.push(propsData.prop)

      const scopedSlotsDefault: NormalizedScopedSlot | undefined = slot.componentInstance?.$scopedSlots.default
      this.templates[propsData.prop] = scopedSlotsDefault
    })

    this.rows = this.data.map(item => {
      const row: TableTdData[] = []
      this.props.forEach(prop => {
        row.push({
          text: item[prop],
          scopedSlot: this.templates[prop],
          data: item,
        })
      })
      return row
    })
  }

  parseSlot(tdData: TableTdData, index: number): ScopedSlotChildren | string {
    if (typeof tdData.scopedSlot === 'function') {
      return tdData.scopedSlot({
        $text: tdData.text,
        $row: tdData.data,
        $index: index,
      })
    } else {
      return tdData.text
    }
  }
}
</script>

<style>
.table,
.table th,
.table td {
  border: 1px solid #000;
}

.table {
  margin: 0 auto;
  border-collapse:collapse;
}

.table th,
.table td {
  padding: 10px;
}
</style>
